package com.steakliu.sun.server;

import com.steakliu.sun.annotation.SunService;
import com.steakliu.sun.common.helper.SunServiceHelper;
import com.steakliu.sun.common.meta.ServiceMeta;
import com.steakliu.sun.common.thread.ServerConcurrentThreadPool;
import com.steakliu.sun.common.util.ServiceUtil;
import com.steakliu.sun.invoker.api.Invoker;
import com.steakliu.sun.registry.api.RegistryConfig;
import com.steakliu.sun.registry.api.RegistryService;
import com.steakliu.sun.server.api.ServerConfig;
import com.steakliu.sun.server.api.ServerLocalServiceCaches;
import com.steakliu.sun.server.netty.NettyServer;
import com.steakliu.sun.spi.loader.ExtensionLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.HashMap;
import java.util.Map;

/**
 * 功能说明：
 * <p>
 * Original @Author: steakliu-刘牌, 2023-01-14  13:25
 * <p>
 * Copyright (C)2020-2022  steakliu All rights reserved.
 */
public class SpringNettyServer implements ApplicationContextAware, InitializingBean {

    private final Logger LOGGER = LoggerFactory.getLogger(SpringNettyServer.class);

    private final ServerConfig serverConfig;

    private final Map<String, ServerLocalServiceCaches> localCacheServices = new HashMap<>();

    private final RegistryService registryService;

    private final Invoker invoker;

    private final ServerConcurrentThreadPool serverConcurrentThreadPool;


    public SpringNettyServer(String host, int port, String registryType, String registryAddress, String reflect,
                             String token, int heartbeatInterval, int heartbeatRetries, int bossGroupThreads,
                             int workGroupThreads, boolean useFlowControl, String flowControlType,
                             int concurrentCorePoolSize, int concurrentMaximumPoolSize, int maxConnections,
                             String connectionsDisuseStrategyType, boolean useRateLimit, String rateLimiterType,
                             int milliseconds,int permits,String rateLimiterFailStrategy, boolean enableBuffer, String bufferType,
                             boolean enableResultCache, int resultCacheTime) throws Exception {
        this.serverConfig = new ServerConfig(host, port, null, registryType, registryAddress, reflect, token,
                heartbeatInterval, heartbeatRetries, bossGroupThreads, workGroupThreads, useFlowControl, flowControlType,
                concurrentCorePoolSize, concurrentMaximumPoolSize,maxConnections, connectionsDisuseStrategyType,useRateLimit,
                rateLimiterType, milliseconds,permits,rateLimiterFailStrategy, enableBuffer, bufferType, enableResultCache, resultCacheTime);
        //构建注册中心
        RegistryService registryService = ExtensionLoader.getExtension(RegistryService.class, registryType);
        registryService.init(new RegistryConfig(registryAddress));
        this.registryService = registryService;
        //构建反射调用
        this.invoker = ExtensionLoader.getExtension(Invoker.class, reflect);
        this.serverConcurrentThreadPool = ServerConcurrentThreadPool.getInstance(concurrentCorePoolSize, concurrentMaximumPoolSize);
        LOGGER.info("使用Spring整合Sun");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        Map<String, Object> annotations = applicationContext.getBeansWithAnnotation(SunService.class);
        annotations.values().forEach(bean -> {
            SunService sunService = bean.getClass().getAnnotation(SunService.class);
            String serviceName = ServiceUtil.getServiceName(sunService);
            LOGGER.info("注册服务，服务名为:  {}", serviceName);
            String version = sunService.version();
            String group = sunService.group();
            String tag = sunService.tag();
            int weight = sunService.weight();
            String token = sunService.token();
            //注册服务到注册中心
            ServiceMeta serviceMeta = new ServiceMeta(serviceName, serverConfig.getHost(), serverConfig.getPort(), version, group, tag, weight);
            try {
                registryService.register(serviceMeta);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //将服务存储进本地缓存
            String key = SunServiceHelper.getServiceKey(serviceName, version, group);
            ServerLocalServiceCaches serverLocalServiceCaches = new ServerLocalServiceCaches();
            serverLocalServiceCaches.setServiceBean(bean);
            serverLocalServiceCaches.setToken(token);
            localCacheServices.put(key, serverLocalServiceCaches);
        });
    }

    @Override
    public void afterPropertiesSet() {
        NettyServer nettyServer = new NettyServer(localCacheServices, invoker, serverConfig, serverConcurrentThreadPool);
        nettyServer.startServer();
    }
}
